<!DOCTYPE html>
<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="content-type">
    <title>ch07-04</title>
    <link href="css/style.css" rel="stylesheet" type="text/css">
    <link rel="stylesheet" href="thumbnailviewer.css" type="text/css">
    <script src="thumbnailviewer.js" type="text/javascript">

/***********************************************
* Image Thumbnail Viewer Script- © Dynamic Drive (www.dynamicdrive.com)
* This notice must stay intact for legal use.
* Visit http://www.dynamicdrive.com/ for full source code
***********************************************/

</script> </head>
  <body>
    <div class="os1">7.4 串行化数据流QDataStream</div>
    <br>
    上节 QTextStream 是针对文本流的处理，QTextStream 中都是人类直接可读的文本形式，但是 QTextStream 有它的局限性，对于
    Qt 自己的类对象，QTextStream 仅支持字符相关的 QChar、QString、QByteArray，Qt 还有很多其他类，比如矩形
    QRect、像素图 QPixmap、点 QPoint、颜色 QColor 等等，这些都没有规定的字符串形式。<br>
    实际程序中会大量用到人类不可读的二进制数据，这些二进制数据的封装和存储、传输，就需要用串行化数据流 QDataStream 实现，对于 Qt
    知道的所有数据类型，包括 C++ 基本类型变量和 Qt 自己类对象，都可以使用 QDataStream
    自动打包成整体的数据块（将各种类型变量和对象按顺序打包就是串行化，按顺序解包就是反串行化），可以用于网络传输和本地文件读写。<br>
    本节先介绍 QDataStream 类的内容，然后编写一个使用 QDataStream 自定义文件格式做输入输出的例子。对于网络数据的封包解包示范，等到
    网络传输章节再介绍，目前可以回顾 3.4.3 节的串行化打包例子。本节最后介绍第二个例子，自定义一个结构体，然后让我们自己的结构体支持串行化输入输出。<br>
    <br>
    <div class="os2">7.4.1 QDataStream 类</div>
    <br>
    QDataStream 可以支持对输入输出设备的串行化，也可以支持对 QByteArray 字节数组的输入输出，它的构造函数如下：<br>
    <div class="code"> QDataStream(QIODevice * d)</div>
    <div class="code"> QDataStream(QByteArray * a, QIODevice::OpenMode mode) </div>
    <div class="code"> QDataStream(const QByteArray &amp; a)</div>
    第一个构造函数是用于支持 I/O 设备，需要在传递指针给 QDataStream 之前把设备打开，比如提前打开文件，然后把文件对象指针传给
    QDataStream。<br>
    第二个构造函数一般用于支持 QByteArray 的读写，传递字节数组的指针，并且需要指定读写模式，一般是用 QIODevice::ReadWrite。<br>
    第三个构造函数参数为字节数组的常量引用，字节数组是只读的，仅作为输入来使用。<br>
    除了构造函数，还有如下设置函数改变当前 QDataStream 对象的设备：<br>
    <div class="code">void QDataStream::​setDevice(QIODevice * d)</div>
    <br>
    QDataStream 使用的是 Qt 自定义的数据打包格式，这种数据打包格式与操作系统、硬件是 100% 无关的，用 QDataStream
    打包的数据包，无论是在 Intel + Windows 、还是 Sun SPARC + Solaris、ARM + Andorid
    等等，都可以通用，不用管 CPU 字节序。<br>
    对于所有 C++ 基本类型变量，QDataStream 提供了一系列的 &lt;&lt; 和 &gt;&gt;&nbsp; 运算符重载函数，比如整型的：<br>
    <div class="code">QDataStream &amp; QDataStream::​operator&lt;&lt;(qint32 i)</div>
    <div class="code">QDataStream &amp; QDataStream::​operator&gt;&gt;(qint32
      &amp; i)</div>
    这些都是 QDataStream 的成员函数，还有其他的比如输入输出 bool、qint64、float、double 等等。<br>
    <br>
    对于 C++ 整型数的读写，需要特别注意 long 类型，在 32 位系统，long 类型是 32 bit 长度，而在 64 位系统，long 是 64
    bit 长度，因为这种不确定性，所以整型变量都应该转为 Qt
    预定义的类型：qint8、quint8、qint16、quint16、qint32、quint32、qint64、quint64，这样能保证变量的长度是类型名字
    里指定的位数，无论在什么操作系统都不会出错。<br>
    <br>
    对于所有 Qt 数据封装类的对象，在 QDataStream 类里面查不到对应的运算符重载函数，不是没有，而是太多。在 Qt 帮助文档 <span style="font-weight: bold;">Serializing
      Qt Data Types </span>页面可以看到所有可以串行化的类型，Qt 自己类对象的串行化，是通过相关的非成员函数（Related
    Non-Members），这些非成员函数可以在各个数据封装类自己的文档页面找到，比如 QColor 类的非成员函数：<br>
    <div class="code">QDataStream &amp; operator&lt;&lt;(QDataStream &amp;
      stream, const QColor &amp; color)</div>
    <div class="code">QDataStream &amp; operator&gt;&gt;(QDataStream &amp;
      stream, QColor &amp; color)</div>
    <br>
    对于 QDataStream 流的输入，可以判断当前位置是否到达设备的末尾：<br>
    <div class="code">bool QDataStream::​atEnd() const</div>
    但是 QDataStream 没有 seek() 函数移动游标，也没有游标获取函数 pos() ，这与文本流 QTextStream、文件类 QFile
    有很大的区别。在 QDataStream 流里看不到游标，因为它不是按字节或字符读写的，它用 Qt 自家的打包格式（或叫编码方式），只能按变量或类对象顺
    序读写，不能随机读写。<br>
    串行化，就如它的名字一样，一条道走到黑，输入输出的顺序固定好之后，就不能进行随机位置读写，只能从头按顺序读或从头按顺序写。<br>
    <br>
    除了 &lt;&lt; 和 &gt;&gt; 运算符重载函数，QDataStream 提供了另外几个读写函数，可以用于读写自定义的数据块，首先是一对
    writeBytes() 和 readBytes() 函数：<br>
    <div class="code">QDataStream &amp; QDataStream::​writeBytes(const char * s,
      uint len) //变量 len 也会写入数据流</div>
    <div class="code">QDataStream &amp; QDataStream::​readBytes(char *&amp; s,
      uint &amp; l)&nbsp; // l 数值是从数据流里读出来的，就是上面的 len</div>
    对于字节写入函数，参数里的 s 是要输出的字节缓冲区，len 是写入数据的长度，这里 s 里面针对纯字节数据，不管里面有没有 '\0' ，都写入
    数据流。<br>
    对于字节读取函数，s 是指针变量的引用，l 是读取的字节数，s 指针不需要程序员分配空间，由 ​readBytes() 函数自己 new []
    一段缓冲区，然后把缓冲区指针赋值给 s；参数 l 是函数的返回变量，是真实读取到的字节数。函数返回之后 s 指针变量指向的缓冲区需程序员手动
    delete [] 。<br>
    ​writeBytes() 函数在做串行化时，会先写 quint32 类型的数据长度，然后写入真实的缓冲区数据到数据流。​readBytes()
    也是先读取字节数组长度，该函数自己 new [] 一片空间，把后面的真实数据读到缓冲区。<br>
    <br>
    writeBytes() 和 ​readBytes() 函数与字符串 读写运算符重载函数有类似的地方：<br>
    <div class="code">QDataStream &amp; QDataStream::​operator&lt;&lt;(const
      char * s) </div>
    <div class="code">QDataStream &amp; QDataStream::​operator&gt;&gt;(char
      *&amp; s)</div>
    在做串行化时，都是先写一个 quint32 类型的长度到数据流，然后写真实数据，读的时候就是先读长度，然后根据长度 new []&nbsp;
    缓冲区，把数据读到缓冲区。这两对函数的区别就是 writeBytes() 和 ​readBytes() 针对字节数组，不管是不是 '\0'，都当作普通字
    节读写；&lt;&lt; 和 &gt;&gt; 读写字符串时遇到 '\0'&nbsp; 就截止了，并且 '\0' 不会写入到数据流。<br>
    <br>
    QDataStream 还提供了更裸的读写函数，下面这对读写函数是不把字节数组长度变量写入到数据流的，仅仅写入原始的缓冲区数据：<br>
    <div class="code">int QDataStream::​writeRawData(const char * s, int len)</div>
    <div class="code">int QDataStream::​readRawData(char * s, int len)</div>
    这对函数与之前一对 writeBytes() 和 ​readBytes()
    函数区别有两点：第一，不写数据长度变量到数据流，只读写最原始的数据块；第二，​readRawData()
    自己不会分配缓冲区，必须由程序员提前分配缓冲区给 s，然后传递给 readRawData() 函数。<br>
    <br>
    QDataStream 与 QTextStream
    也有类似的地方，就是流的状态，如果数据流的输入顺序与输出顺序不匹配，那么会出现状态错误，获取流的状态函数为：<br>
    <div class="code">Status QDataStream::​status() const</div>
    状态枚举类型也有四个：<br>
    <br>
    <table class="tabel">
      <tbody>
        <tr class="d1">
          <td style="width: 200px;" align="center"><b>Status 枚举常量</b></td>
          <td style="width: 200px;" align="center"><b>数值</b></td>
          <td align="center"><b> 描述</b></td>
        </tr>
        <tr>
          <td>QDataStream::Ok</td>
          <td> 0 </td>
          <td> 正常操作状态，没出错。 </td>
        </tr>
        <tr class="d1">
          <td>QDataStream::ReadPastEnd</td>
          <td> 1 </td>
          <td> 底层设备已到达末尾，比如文件末尾，无数据可读了。 </td>
        </tr>
        <tr>
          <td>QDataStream::ReadCorruptData</td>
          <td> 2 </td>
          <td> 读入了腐化数据，典型的就是输入流读取顺序与输出流顺序不一样。</td>
        </tr>
        <tr class="d1">
          <td>QDataStream::WriteFailed</td>
          <td> 3 </td>
          <td> 无法向底层设备写入数据，比如文件是只读的。 </td>
        </tr>
      </tbody>
    </table>
    <br>
    在 QDataStream 数据流出现错误状态之后，可以重新设置流的状态：<br>
    <div class="code">void QDataStream::​setStatus(Status
      status)&nbsp;&nbsp;&nbsp; //设置流为参数里执行的状态</div>
    <div class="code">void QDataStream::​resetStatus()&nbsp;&nbsp;&nbsp;
      //重置为原始的 Ok 状态</div>
    QDataStream 流的排除处理就比较麻烦了，虽然可以跳过一定的裸字节数：<br>
    <div class="code">int QDataStream::​skipRawData(int len)</div>
    这个函数跳过最原始的裸数据 len 长度的字节，返回值是真实跳过的字节数。这个函数可以与 ​readRawData()
    配合使用，但是在处理流错误时未必有用，因为跳过指定的字节数目之后，流的数据到哪种类型的变量或对象了，难以确定。QDataStream
    读取错误时，最好的做法是直接提示出错，后面的不读取，因为串行化数据流默认是不能随机化读写的。<br>
    <br>
    QDataStream 是使用 Qt 自己独有的串行化数据打包方式，它没有任何的格式操作子，因为输入输出格式全是内置的，但 QDataStream
    有自己兼容的 Qt 版本号。随着 Qt 版本的更新，QDataStream 打包数据的方式也会更新，因此 QDataStream
    有一大堆兼容的版本号，从最早的 Qt_1_0 到最新的 Qt_5_4，版本号枚举常量的命名规则就是&nbsp; <span style="font-style: italic;">Qt_
      大版本号_小版本号</span> 。<br>
    如果负责输出的程序与负责输入的程序，使用的 Qt 版本是一致的，就不需要设置版本号。但是如果输出和输入程序的 Qt&nbsp; 版本不一致，比如输出程序
    使用的是 Qt 4.8.* ，输入程序使用的是 Qt 5.4.* ，那么就应该向旧版本兼容，在做读取变量或对象之前，设置版本号：<br>
    <div class="code">void QDataStream::​setVersion(int v)</div>
    要兼容 Qt 4.8.* ，那么就把参数设为 QDataStream::Qt_4_8&nbsp; 。<br>
    <br>
    随着 Qt 版本号的更新，C++ 基本类型的变量读写规则是固定的，比如 qint32 就是读写 4 个字节，所以 QDataStream 版本号对
    C++ 基本类型变量读写其实没影响。QDataStream 版本号影响的是 Qt 自己类对象的读写规则，比如以后如果新增了一个类
    QXXXXData，那么只有新版本的 Qt 中 QDataStream 才能读写这个新类 QXXXXData 对象。<br>
    <br>
    在本小节末尾，我们将 QTextStream 和 QDataStream 简单做一下对比：<br>
    <br>
    <table class="tabel">
      <tbody>
        <tr class="d1">
          <td style="width: 200px;" align="center"><b>对比项</b></td>
          <td style="width: 400px;" align="center"><b>QTextStream</b></td>
          <td style="width: 400px;" align="center"><b> QDataStream</b></td>
        </tr>
        <tr>
          <td>用途</td>
          <td> 处理文本流，如 QIODevice、FILE句柄、QString、QByteArray，这里的 QByteArray
            是作为字符串用途，以 '\0' 为终止符 </td>
          <td> 处理二进制数据流，如 QIODevice 、QByteArray ，这里的 QByteArray
            作为字节数组，是纯数据，不区分字节数值是否为 0</td>
        </tr>
        <tr class="d1">
          <td>&lt;&lt; 和 &gt;&gt; 涵盖的数据类型</td>
          <td> C++基本类型和 QChar、QString、QByteArray（字符串）</td>
          <td> C++基本类型和 Qt 库中几乎所有用于表示数据的类</td>
        </tr>
        <tr>
          <td>流操作子</td>
          <td> 很多格式化操作子，程序员可以控制格式</td>
          <td> 没有操作子，打包格式内定，程序员不能控制</td>
        </tr>
        <tr class="d1">
          <td>流的版本号</td>
          <td> 没有版本号 </td>
          <td> 可以设置从 Qt_1_0 到最新的版本号，不同版本号的串行化打包是有区别的</td>
        </tr>
        <tr>
          <td>流的游标</td>
          <td> pos() 获取游标，seek() 移动游标，atEnd() 判断末尾，可以随机化读写</td>
          <td> 没有游标，只能用 atEnd() 判断是否到末尾，不能随机化读写，必须按写入时相同的顺序和类型来读取</td>
        </tr>
        <tr class="d1">
          <td>流的工作状态</td>
          <td> QTextStream::Status 四种状态</td>
          <td> QDataStream::​Status 四种状态</td>
        </tr>
      </tbody>
    </table>
    <br>
    从上面表格可以看到，QTextStream 和 QDataStream 除了都有四种工作状态，其他特性都有差异，二者用途不同，决定差异性很大。<br>
    <br>
    <div class="os2">7.4.2 自定义文件格式输入输出</div>
    <br>
    我们在 7.3.5
    节例子中表格数据，是采用文本形式存储的，本小节我们自定义一个二进制文件格式，专门存储类似下面的数据表格（下面表格是文本的，只是方便大家看，真实的二进制文件我们例
    子结尾用 QtCreator 打开看）：<br>
    <div class="code">#QString qint32&nbsp; double<br>
      小明&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 18&nbsp;&nbsp;&nbsp;&nbsp; 50.5<br>
      小萌&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 19&nbsp;&nbsp;&nbsp;&nbsp; 55.8<br>
      小日&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 17 &nbsp; &nbsp; 60.0<br>
      小月&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 16 &nbsp; &nbsp; 55.1<br>
      小草&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 18&nbsp;&nbsp;&nbsp;&nbsp; 58.6</div>
    因为用二进制数据格式，就不用注释行了，只需要用 QDataStream 写入指定类型数据。<br>
    我们这里自定义文件扩展名设置为 .ds ，一般文件都需要一些文件头的结构体信息，我们这里使用 QDataStream 输出文件信息头，我们定义 .ds
    文件结构如下：<br>
    <center> <img src="images/ch07/ch07-04-01.png" alt="ds file"> </center>
    文件首先是一个 qint16 变量，数值为 0x4453，就是字母 'D' 和 'S' 的十六进制数，打头的 0x4453 一般称为魔力数字（magic
    number），用于标识文件类型；<br>
    然后也是一个 qint16 变量，数值为 0x0100，代表文件格式 1.0 版本；<br>
    接着是表格数据的总行数计数 nCount ，之后就是每行的数据（不是文本文件不需要写入换行符，这里的“行”只是方便理解数据的排布）。<br>
    文件的写入和读取都用 QDataStream 实现，为了向旧版本的 Qt 兼容，我们这里规定文件格式 1.0&nbsp; 版本对应的
    QDataStream 都用 Qt_4_8 的版本号。<br>
    <br>
    讲完自定义文件格式，下面我们开始编写示例程序，打开 QtCreator，新建一个 Qt Widgets Application
    项目，在新建项目的向导里填写：<br>
    ①项目名称 dsedit，创建路径 D:\QtProjects\ch07，点击下一步；<br>
    ②套件选择里面选择全部套件，点击下一步；<br>
    ③基类选择 QWidget，点击下一步；<br>
    ④项目管理不修改，点击完成。<br>
    我们打开 widget.ui 界面文件，先把主界面窗口的尺寸设置为 480*300，然后按照下图拖入控件：<br>
    <center> <img src="images/ch07/ch07-04-02.png" alt="ui" width="800"> </center>
    界面从左边看是两大行控件：<br>
    第一大行，标签控件，文本 "姓名"，单行编辑器，对象名 lineEditName，标签控件，文本 "年龄"，单行编辑器，对象名
    lineEditAge，标签控件，文本 "体重"，单行编辑器，对象名 lineEditWeight，最右边是按钮控件，对象名
    pushButtonAdd，文本为 "添加行" ，第一大行按照水平布局器排布。<br>
    第二大行，左边是一个列表控件，对象名默认为 listWidget；右边是一个垂直布局器，在垂直布局里是三个按钮和垂直弹簧条，首先是 "删除行"
    按钮，对象名 pushButtonDel，垂直弹簧条，对象名默认为 verticalSpacer，然后是 "保存DS" 按钮，对象名
    pushButtonSaveDS，最下面是 "加载DS" 按钮，对象名为 pushButtonLoadDS，第二大行也是按照水平布局器排布。<br>
    窗口的主布局器是垂直布局器，点击界面空白位置，不选中任何控件，再点击上面垂直布局按钮就可以为窗口设置主布局器。这个例子界面与 7.3
    节第一个例子相比做了调整，因为本节的 DS 文件原本没有，是我们自创的格式，需要手动在示例程序添加各行数据，然后保存为 *.ds 才会生成 DS 文件。<br>
    <br>
    界面和布局就是如上所述，现在我们分四次为四个按钮都添加 clicked() 信号对应的槽函数：<br>
    <center> <img src="images/ch07/ch07-04-03.png" alt="slot1"> </center>
    然后为列表控件 listWidget 添加 currentRowChanged(int) 信号对应的槽函数：<br>
    <center> <img src="images/ch07/ch07-04-04.png" alt="slot5"> </center>
    添加好槽函数之后，我们保存界面文件，然后关闭界面文件，回到代码编辑模式。<br>
    对于头文件 widget.h ，不需要手动添加代码，都是自动生成的，下面仅仅贴出来看看：<br>
    <div class="code"><span style=" color:#000080;">#ifndef</span><span style=" color:#c0c0c0;">
      </span>WIDGET_H
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#define</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">WIDGET_H</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QWidget&gt;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">namespace</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Ui</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">class</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Widget</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">class</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Widget</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">:</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">public</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QWidget</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">Q_OBJECT</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">public</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">explicit</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QWidget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span>parent<span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">~</span><span style=" font-style:italic; color:#000000;">Widget</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">private</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">slots</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_pushButtonAdd_clicked</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_pushButtonDel_clicked</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_pushButtonSaveDS_clicked</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_pushButtonLoadDS_clicked</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_listWidget_currentRowChanged</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span>currentRow<span
style=" color:#000000;">);</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">private</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Ui</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Widget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">};</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#endif</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">WIDGET_H</span></pre>
    </div>
    头文件有五个槽函数，我们需要在 widget.cpp 里面添加功能代码，下面我们打开 widget.cpp ，首先添加头文件包含和构造函数里的代码：<br>
    <div class="code"><span style=" color:#000080;">#include</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#008000;">"widget.h"</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">"ui_widget.h"</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QDebug&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QMessageBox&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QFileDialog&gt;</span><span style=" color:#c0c0c0;">  </span><span
style=" color:#008000;">//文件对话框</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QFile&gt;</span><span style=" color:#c0c0c0;">        </span><span
style=" color:#008000;">//文件类</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QDataStream&gt;</span><span style=" color:#c0c0c0;">  </span><span
style=" color:#008000;">//串行化数据流，用于读写</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">.ds</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">文件</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QTextStream&gt;</span><span style=" color:#c0c0c0;">  </span><span
style=" color:#008000;">//用于列表控件显示的文本和数据转换</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QListWidgetItem&gt;//用于从列表控件的行提取文本</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
style=" color:#000000;">Widget</span><span style=" color:#000000;">(</span><span
style=" color:#800080;">QWidget</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">*</span><span style=" color:#000000;">parent</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QWidget</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">parent</span><span
style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">new</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Ui</span><span style=" color:#000000;">::</span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setupUi</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//设置列表控件只能选中一行，简化删除行的操作</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">listWidget</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setSelectionMode</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QAbstractItemView</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">SingleSelection</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#800080;">Widget</span><span style=" color:#000000;">::~</span><span
style=" font-style:italic; color:#000000;">Widget</span><span style=" color:#000000;">()</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">delete</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">ui</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    头文件增加了上一节用到过的文件对话框，文件类、文本流等，&lt;QListWidgetItem&gt;
    是用于从列表控件的行里提取文本用的，&lt;QDataStream&gt; 是本节的串行化数据流。<br>
    构造函数里只增加了一句代码，用于设置列表控件为每次只能选中一行，这样删除行时只需要删除一行，简化操作。<br>
    <br>
    接下来是四个按钮对应的槽函数代码，先看看 "添加行" 按钮对应的槽函数：<br>
    <div class="code"><span style=" color:#808000;">void</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
        style=" color:#000000;">on_pushButtonAdd_clicked</span><span style=" color:#000000;">()</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strName</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">lineEditName</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">text</span><span style=" color:#000000;">().</span><span
style=" color:#000000;">trimmed</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strAge</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">lineEditAge</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">text</span><span style=" color:#000000;">().</span><span
style=" color:#000000;">trimmed</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strWeight</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">lineEditWeight</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">text</span><span style=" color:#000000;">().</span><span
style=" color:#000000;">trimmed</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断三个数据项是否为空</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strName</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">isEmpty</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">||</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strAge</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">isEmpty</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">||</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strWeight</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">isEmpty</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"添加行"</span><span style=" color:#000000;">),</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"请填好姓名、年龄、体重三个数据项再添加。"</span><span style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//计算出年龄和体重</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">qint32</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nAge</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strAge</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">toInt</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">double</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dblWeight</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">strWeight</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">toDouble</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断范围</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">(</span><span
style=" color:#000000;">nAge</span><span style=" color:#000000;">&lt;</span><span
style=" color:#000080;">0</span><span style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">||</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">(</span><span
style=" color:#000000;">nAge</span><span style=" color:#000000;">&gt;</span><span
style=" color:#000080;">600</span><span style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"添加行"</span><span style=" color:#000000;">),</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"年龄数值不对，应该</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">0~600</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">"</span><span style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dblWeight</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&lt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0.1</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"添加行"</span><span style=" color:#000000;">),</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"体重数值不对，至少</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">0.1kg</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">"</span><span style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//对于正常数据，添加新行到列表控件</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strAll</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QTextStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tsLine</span><span
style=" color:#000000;">(&amp;</span><span style=" color:#000000;">strAll</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">tsLine</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">strName</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#008000;">"\t"</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">nAge</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#008000;">"\t"</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">         </span><span style=" color:#000000;">&lt;&lt;</span>fixed<span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">qSetRealNumberPrecision</span><span
style=" color:#000000;">(</span><span style=" color:#000080;">2</span><span style=" color:#000000;">)&lt;&lt;</span><span
style=" color:#000000;">dblWeight</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">listWidget</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">addItem</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strAll</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    这个槽函数先获取三个单行编辑器的文本，判断文本是否有空串，如果全部非空，再继续后面操作。<br>
    对于三个非空字符串，根据年龄、体重的字符串转为数值 nAge、dblWeight ，然后对年龄、体重数值做一下简单判断。<br>
    nAge、dblWeight 经过判断之后，我们定义字符串 strAll，用于保存三个数据项生成的文本，我们用文本流 tsLine
    将三个数据项按照指定格式输出到 strAll 里面，最后把 strAll 添加到列表控件。<br>
    <br>
    "删除行" 按钮对应的槽函数代码就很简单了：<br>
    <div class="code"><span style=" color:#808000;">void</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
        style=" color:#000000;">on_pushButtonDel_clicked</span><span style=" color:#000000;">()</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取列表控件选中的行</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">int</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCurRow</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">listWidget</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">currentRow</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断序号是否合法</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCurRow</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&lt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">//没有选中行</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//对于正常选中的行，删除掉</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">listWidget</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">takeItem</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCurRow</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    判断当前行号，然后删除列表控件里面的行即可。<br>
    <br>
    接着是 "保存DS" 按钮对应的槽函数，里面有写入 DS 文件格式代码：<br>
    <div class="code"><span style=" color:#808000;">void</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
        style=" color:#000000;">on_pushButtonSaveDS_clicked</span><span style=" color:#000000;">()</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//总行数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">int</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCount</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">listWidget</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">count</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断是否有数据</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">nCount</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&lt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">1</span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">//没数据，不用写</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取要保存的文件名</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strFileName</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">QFileDialog</span><span style=" color:#000000;">::</span><span
style=" color:#000000;">getSaveFileName</span><span style=" color:#000000;">(</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#808000;">this</span><span
style=" color:#000000;">,</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"保存为</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">DS</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">文件"</span><span
style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"."</span><span style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"DS</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">files(*.ds);;All</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">files(*)"</span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strFileName</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">isEmpty</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">//没有保存文件名</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//有保存文件名，打开该文件供写入</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QFile</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">fileOut</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">strFileName</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">!</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">fileOut</span><span
style=" color:#000000;">.</span><span style=" font-style:italic; color:#000000;">open</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QIODevice</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">WriteOnly</span><span
style=" color:#000000;">))</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"无法打开文件"</span><span style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                            </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"无法打开要写入的文件："</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">+</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">fileOut</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">errorString</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//现在有输出文件对象，构造输出流</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">(&amp;</span><span style=" color:#000000;">fileOut</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//设置流的版本</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setVersion</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QDataStream</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Qt_4_8</span><span
style=" color:#000000;">);</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//先写文件头，都用</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">qt</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">定义的整型变量输出</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#800080;">qint16</span><span
style=" color:#000000;">(</span><span style=" color:#000080;">0x4453</span><span
style=" color:#000000;">);</span><span style=" color:#c0c0c0;">  </span><span style=" color:#008000;">//'D'</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">'S'</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#800080;">qint16</span><span
style=" color:#000000;">(</span><span style=" color:#000080;">0x0100</span><span
style=" color:#000000;">);</span><span style=" color:#c0c0c0;">  </span><span style=" color:#008000;">//1.0版本文件格式</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#800080;">qint32</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">nCount</span><span
style=" color:#000000;">);</span><span style=" color:#c0c0c0;">  </span><span style=" color:#008000;">//行计数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//每行的三个数据项</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strCurName</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">qint32</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCurAge</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">double</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dblCurWeight</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//从列表控件按行读取数据，然后写入到文件</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">for</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">i</span><span style=" color:#000000;">=</span><span style=" color:#000080;">0</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">i</span><span
style=" color:#000000;">&lt;</span><span style=" color:#000000;">nCount</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">i</span><span
style=" color:#000000;">++)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strLine</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">listWidget</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">item</span><span style=" color:#000000;">(</span><span style=" color:#000000;">i</span><span
style=" color:#000000;">)-&gt;</span><span style=" color:#000000;">text</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QTextStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tsLine</span><span
style=" color:#000000;">(&amp;</span><span style=" color:#000000;">strLine</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//从该行文本提取三个数据项</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">tsLine</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">strCurName</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">nCurAge</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">dblCurWeight</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//写入到文件</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">strCurName</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">nCurAge</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">dblCurWeight</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//提示写入完毕</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">information</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"保存DS文件"</span><span style=" color:#000000;">),</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"保存为</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">.ds</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">文件成功！"</span><span
style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    这个槽函数先判断列表控件的数据行数，没数据就不处理。<br>
    接着获取要保持的文件名，并判断文件名是否为空。<br>
    有保存文件名之后，定义文件对象 fileOut，并以只写模式打开文件。<br>
    打开文件成功之后构造串行化输出流 dsOut，设置流的版本号为 QDataStream::Qt_4_8。<br>
    接下来是自定文件格式的写入，写入魔力数字 0x4453、版本号 0x0100 和 数据的行数 nCount。<br>
    写入文件时，需要注意把整型数都转成 Qt 定义的 qint16、qint32 等类型，明确占用的比特位数。<br>
    接着就是每个数据行的写入过程，使用 for 循环取出列表控件每行的文本 strLine ，<br>
    然后根据文本 strLine 指针定义文本流 tsLine，从 tsLine 提取三个数据项
    strCurName、nCurAge、dblCurWeight。<br>
    得到三个数值变量之后，按顺序写入串行化输出流 dsOut 。<br>
    注意我们这里说的一行数据只是个概念，没有真的写入换行符，因为二进制文件读写压根不用换行符，"行" 这个字仅仅是方便理解数据的排布而已。<br>
    写完所有行的数据之后，弹出消息框，提示保存完毕。<br>
    <br>
    与保存文件函数相反的，就是 "加载DS" 按钮对应的槽函数：<br>
    <div class="code"><span style=" color:#808000;">void</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
        style=" color:#000000;">on_pushButtonLoadDS_clicked</span><span style=" color:#000000;">()</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取要打开的文件名</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strFileName</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">QFileDialog</span><span style=" color:#000000;">::</span><span
style=" color:#000000;">getOpenFileName</span><span style=" color:#000000;">(</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#808000;">this</span><span
style=" color:#000000;">,</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"打开DS文件"</span><span
style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"."</span><span style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"DS</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">files(*.ds);;All</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">files(*)"</span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断文件名</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strFileName</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">isEmpty</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//文件对象</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QFile</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">fileIn</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strFileName</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//打开</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">!</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">fileIn</span><span
style=" color:#000000;">.</span><span style=" font-style:italic; color:#000000;">open</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QIODevice</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">ReadOnly</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//打开失败</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"打开DS文件"</span><span style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                             </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"打开DS文件失败:</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"</span><span style=" color:#000000;">)</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">+</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">fileIn</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">errorString</span><span style=" color:#000000;">());</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//构造输入数据流</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dsIn</span><span style=" color:#000000;">(&amp;</span><span
style=" color:#000000;">fileIn</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//读取文件头</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">qint16</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nDS</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">qint16</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nVersion</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">qint32</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCount</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">dsIn</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">nDS</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">nVersion</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">nCount</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">nDS</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">数值</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000080;">0x4453</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">!=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">nDS</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"打开文件"</span><span style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                             </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"指定的文件不是</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">.ds</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">文件类型，无法加载。"</span><span style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断版本号目前只有</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">1.0</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000080;">0x0100</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">!=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">nVersion</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"打开文件"</span><span style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                             </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"指定的</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">.ds</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">文件格式版本不是</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">1.0，暂时不支持。"</span><span
style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">else</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//设置流的版本</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">dsIn</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setVersion</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Qt_4_8</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断行计数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCount</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&lt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">1</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"打开文件"</span><span style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                             </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"指定的</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">.ds</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">文件内数据行计数小于</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">1，无数据加载。"</span><span
style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//现在行计数也正常</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//三个数据项</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strCurName</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">qint32</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCurAge</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">double</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dblCurWeight</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//先清空列表控件的内容</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">listWidget</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">clear</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//逐行加载数据到列表控件</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">for</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">i</span><span style=" color:#000000;">=</span><span style=" color:#000080;">0</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">i</span><span
style=" color:#000000;">&lt;</span><span style=" color:#000000;">nCount</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">i</span><span
style=" color:#000000;">++)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//每行开头判断输入数据流状态</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dsIn</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">status</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">!=</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Ok</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">            </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"第</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">%1</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">行读取前的状态出错：%2"</span><span
style=" color:#000000;">).</span><span style=" color:#000000;">arg</span><span style=" color:#000000;">(</span><span
style=" color:#000000;">i</span><span style=" color:#000000;">).</span><span style=" color:#000000;">arg</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">dsIn</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">status</span><span style=" color:#000000;">());</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">            </span><span style=" color:#808000;">break</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;">  </span><span style=" color:#008000;">//跳出循环</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//如果现在的状态正常，就加载当前行的数据项</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">dsIn</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">strCurName</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">nCurAge</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">dblCurWeight</span><span
style=" color:#000000;">;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//构造字符串</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strLine</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span style=" color:#008000;">"%1\t%2\t%3"</span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">.</span><span
style=" color:#000000;">arg</span><span style=" color:#000000;">(</span><span style=" color:#000000;">strCurName</span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">.</span><span
style=" color:#000000;">arg</span><span style=" color:#000000;">(</span><span style=" color:#000000;">nCurAge</span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">.</span><span
style=" color:#000000;">arg</span><span style=" color:#000000;">(</span><span style=" color:#000000;">dblCurWeight</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000080;">0</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">'f'</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000080;">2</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//添加到列表控件</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">listWidget</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">addItem</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">strLine</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//提示加载完毕</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">information</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"加载DS文件"</span><span style=" color:#000000;">),</span><span
style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span style=" color:#008000;">"加载DS文件完成！"</span><span
style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    加载文件的过程复杂一些，我们首先获取要打开的文件名，判断文件名是否为空；<br>
    然后定义文件对象 fileIn，以只读模式打开文件；<br>
    打开文件成功之后，根据 fileIn 指针定义串行化输入流 dsIn。<br>
    我们接着还没设置 流的版本号，就先都读取了 nDS、nVersion、nCount 三个整型变量，这是因为 QDataStream 版本号对 C++
    基本类型变量的读写没影响，nDS 和 nVersion 各自占 2 字节，nCount 占 4 字节，这三个基本类型变量可以直接读。<br>
    然后我们先判断魔力数字 nDS 是否为指定的 0x4453 （即 'D' 'S'），不是这个数值就报错；<br>
    接着判断 nVersion 是否为 0x0100 （文件格式版本 1.0），如果不是这个版本就报错，是正确版本就把当前的串行化数据流的版本设置为
    QDataStream::Qt_4_8，后续的读取操作就是按 Qt 4.8.* 兼容模式读了。<br>
    然后再-判断一下行的计数 nCount，如果行数小于 1 就报错。<br>
    对于正常的行数，我们利用 for 循环加载每一行数据，for 循环里面先判断输入流的状态，如果状态出错就停止；<br>
    如果状态正常就读取三个变量 strCurName、nCurAge、dblCurWeight，然后根据三个变量构造字符串 strLine
    ，并添加到列表控件显示该行文本。<br>
    加载完成之后，弹出消息框提示加载完毕。<br>
    <br>
    上面代码从串行化数据流读取变量时，如果流的状态出错，就直接停止循环，不再读取后面内容了，这是简单的排错方式，因为文件内容可能损坏了，程序对修正文件错误是
    无能为力的。<br>
    <br>
    最后来看看列表控件选中行变化时的信号对应的槽函数：<br>
    <div class="code"><span style=" color:#808000;">void</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
        style=" color:#000000;">on_listWidget_currentRowChanged</span><span style=" color:#000000;">(</span><span
        style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span
        style=" color:#000000;">currentRow</span><span style=" color:#000000;">)</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断行号是否合法</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">currentRow</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&lt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//对于正常的行号</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//读取该行文本</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strLine</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">listWidget</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">item</span><span style=" color:#000000;">(</span><span style=" color:#000000;">currentRow</span><span
style=" color:#000000;">)-&gt;</span><span style=" color:#000000;">text</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//构造内存字符串文本流</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QTextStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tsLine</span><span
style=" color:#000000;">(&amp;</span><span style=" color:#000000;">strLine</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//三个数据项</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strName</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">int</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nAge</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">double</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dblWeight</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">tsLine</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">strName</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">nAge</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">dblWeight</span><span
style=" color:#000000;">;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//显示到三个单行编辑器</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditName</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setText</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">strName</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditAge</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"%1"</span><span style=" color:#000000;">).</span><span
style=" color:#000000;">arg</span><span style=" color:#000000;">(</span><span style=" color:#000000;">nAge</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditWeight</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"%1"</span><span style=" color:#000000;">).</span><span
style=" color:#000000;">arg</span><span style=" color:#000000;">(</span><span style=" color:#000000;">dblWeight</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    当选中行变化时，先判断当前的行号是否合法，行号正常之后，获取该行文本，根据文本构造输入流 tsLine，提取三个数据项
    strName、nAge、dblWeight，然后显示到对应的单行编辑器里。<br>
    <br>
    示例代码就是上面那些，我们生成运行例子，然后把本小节开始出的五行数据添加到列表里面：<br>
    <center> <img src="images/ch07/ch07-04-05.png" alt="run"> </center>
    点击 "保存DS" 按钮，把文件存到影子构建文件夹或项目源码文件夹，文件名为 people.ds ，保存好之后，用 QtCreator 打开
    people.ds 文件，可以看到如下内容：<br>
    <center> <img src="images/ch07/ch07-04-06.png" alt="ds file" width="800"> </center>
    DS 文件打开之后，默认按十六进制模式显示，可以按图上标注的看一下写入后的 DS 文件真实内容，打头的就是 0x4453，然后是版本号
    0x0100，接着 qint32 类型的行数，为 5 行。后面还标注了第一行数据的划分 QString、qint32<br>
    和 double 类型变量，后面几行的内容是类似的划分。<br>
    QDataStream 打包数据时，整型变量默认按照大端字节序排列（就是网络字节序），QDataStream 打包使用的字节序不用操心，也不要改，看看就
    行了。<br>
    <br>
    注：小端字节序和大端字节序是网络编程中的基本概念：<br>
    ● 对于我们常见的 Intel 和 AMD 的主机系统，整型数值比如 0x12345678 ，高位字节 0x12 排在内存地址的高址，低位字节 0x78
    排在内存地址的低址，称为小端字节序，这些主机使用的字节序就是主机字节序。<br>
    ● 而网络传输不是这样的，网络中高位字节 0x12 先传输，低位字节 0x78 后传输，高位字节排在内存低址，因此称为大端字节序，也叫网络字节序。以前
    SUN 的主机内部直接使用大端字节序作为主机字节序，只是这类主机差不多绝种了。<br>
    <br>
    <div class="os2">7.4.3 让自定义的结构体支持串行化</div>
    <br>
    本小节例子我们自己定义一个 UDP 头部和报文信息的数据结构，然后让这个结构体支持 QDataStream 串行化输入输出，因为 IP 和 TCP
    头部比较复杂，这里用 UDP 举例子比较简单。C++ 的结构体和类其实是差不多的，结构体成员变量默认是公有的，而类的成员变量默认私有， class 和
    struct 其他的特性都一样，这里用 struct 作例子，如果读者以后让自定义的类支持 QDataStream 也类似地实现就行了。<br>
    网上有很多 UDP 协议的介绍文章，我们将 UDP 的头部和信息用如下结构体表示：<br>
    <div class="code">//UDP 头部和报文<br>
      struct UDPPacker<br>
      {<br>
      &nbsp;&nbsp;&nbsp; quint16 m_srcPort;&nbsp; //源端口<br>
      &nbsp;&nbsp;&nbsp; quint16 m_dstPort;&nbsp; //目的端口<br>
      &nbsp;&nbsp;&nbsp; quint16 m_length;&nbsp;&nbsp; //UDP头部和报文总长度<br>
      &nbsp;&nbsp;&nbsp; quint16 m_checksum; //校验和（不是强制要求）<br>
      &nbsp;&nbsp;&nbsp; QByteArray m_data;&nbsp; //报文内容<br>
      <br>
      &nbsp;&nbsp;&nbsp; //友元声明，一对用于支持QDataStream 输入输出的函数<br>
      &nbsp;&nbsp;&nbsp; friend QDataStream &amp; operator&lt;&lt;(QDataStream
      &amp; stream, const UDPPacker &amp; udp);<br>
      &nbsp;&nbsp;&nbsp; friend QDataStream &amp; operator&gt;&gt;(QDataStream
      &amp; stream, UDPPacker &amp; udp);<br>
      };</div>
    UDP头部里面都是无符号数，按顺序排是两字节的源端口号、两字节的目的端口号、两字节的包长、两字节的校验和，UDP校验和不是强制要求的，我们后面代码就简单
    把校验和设置为 0，校验和之后是 UDP 协议承载的报文内容，我们这里用 QByteArray 类型表示，后面代码报文内容都是字符串，用 UTF-8
    编码的字符串。<br>
    <br>
    为了让结构体或类支持 QDataStream 串行化输入输出，一般是在结构体或类的声明里添加两句友元声明，如上面运算符 &lt;&lt; 和
    &gt;&gt; 的重载函数，把函数的第二个参数的类型改成我们的结构体名或类名的引用，如上面示范的两句友元声明。添加声明之后，我们还需要在 .cpp
    源代码文件实现这两个重载函数，等会例子中再讲。<br>
    <br>
    我们现在开始学习这个例子，重新打开 QtCreator，新建一个 Qt Widgets Application 项目，在新建项目的向导里填写：<br>
    ①项目名称 udppack，创建路径 D:\QtProjects\ch07，点击下一步；<br>
    ②套件选择里面选择全部套件，点击下一步；<br>
    ③基类选择 QWidget，点击下一步；<br>
    ④项目管理不修改，点击完成。<br>
    我们打开 widget.ui 界面文件，先把主界面窗口的尺寸设置为 480*300，然后按照下图拖入控件：<br>
    <center> <img src="images/ch07/ch07-04-07.png" alt="ui" width="800"> </center>
    界面从左边看有三大行控件：<br>
    第一行，标签控件，文本 "源头端口"，单行编辑器，对象名为 lineEditSrcPort，标签控件，文本 "目的端口"，对象名为
    lineEditDstPort，第一行的控件按水平布局器排布。<br>
    第二行，标签控件，文本 "报文消息"，单行编辑器，对象名为 lineEditMsg，第二行也是按水平布局器排布。<br>
    第三行，左边是一个列表控件，对象名 listWidget，右边是一个垂直布局器，里面四个按钮和中间的垂直弹簧条，上面第一个按钮，文本为
    "添加UDP包"，对象名 pushButtonAddUDP，第二个按钮文本为 "删除UDP包"，对象名
    pushButtonDelUDP，然后是垂直弹簧条，对象名默认为 verticalSpacer，再到第三个按钮，文本为 "保存UDP" ，对象名为
    pushButtonSave，第四个按钮的文本为 "加载UDP"，对象名 pushButtonLoad 。第三大行也是按水平布局器排布。<br>
    主界面是以垂直布局器作为主布局器。<br>
    <br>
    接着我们为分四次为四个按钮都添加 clicked() 信号对应的槽函数：<br>
    <center> <img src="images/ch07/ch07-04-08.png" alt="slot1"> </center>
    然后我们为列表控件 listWidget 添加 currentRowChanged(int) 信号对应的槽函数：<br>
    <center> <img src="images/ch07/ch07-04-09.png" alt="slot5"> </center>
    添加好上述槽函数之后，保存界面文件，关闭界面文件，回到 QtCreator 代码编辑模式。<br>
    我们先在头文件 widget.h 添加自定义结构体的声明代码，完整的 widget.h 代码如下：<br>
    <div class="code"><span style=" color:#000080;">#ifndef</span><span style=" color:#c0c0c0;">
      </span>WIDGET_H
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#define</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">WIDGET_H</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QWidget&gt;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#008000;">//网络协议头一般都用</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">1</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">字节对齐</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#pragma</span><span style=" color:#c0c0c0;"> </span>pack(1)</pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#008000;">//UDP</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">头部和报文</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">struct</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">UDPPacker</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">quint16</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_srcPort</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;">  </span><span style=" color:#008000;">//源端口</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">quint16</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_dstPort</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;">  </span><span style=" color:#008000;">//目的端口</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">quint16</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_length</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;">   </span><span style=" color:#008000;">//UDP头部和报文总长度</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">quint16</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_checksum</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">//校验和（不是强制要求）</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QByteArray</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_data</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;">  </span><span style=" color:#008000;">//报文内容</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//友元声明，一对用于支持QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">输入输出的函数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">friend</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">operator</span><span
style=" color:#000000;">&lt;&lt;(</span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#c0c0c0;"> </span>stream<span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#808000;">const</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">UDPPacker</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#c0c0c0;"> </span>udp<span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">friend</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">operator</span><span
style=" color:#000000;">&gt;&gt;(</span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#c0c0c0;"> </span>stream<span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">UDPPacker</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#c0c0c0;"> </span>udp<span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">};</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">namespace</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Ui</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">class</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Widget</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">class</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Widget</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">:</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">public</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QWidget</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">Q_OBJECT</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">public</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">explicit</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QWidget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span>parent<span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">~</span><span style=" font-style:italic; color:#000000;">Widget</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">private</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">slots</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_pushButtonAddUDP_clicked</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_pushButtonDelUDP_clicked</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_pushButtonSave_clicked</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_pushButtonLoad_clicked</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_listWidget_currentRowChanged</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span>currentRow<span
style=" color:#000000;">);</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">private</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Ui</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Widget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">};</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#endif</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">WIDGET_H</span></pre>
    </div>
    在 UDPPacker 结构体声明之前，先加一句 #pragma pack(1) ，告诉编译器对结构体成员变量按照 1
    字节对齐，一般网络协议的头部都是按 1 字节对齐，不能用编译器默认的 4 字节对齐。<br>
    UDPPacker 的声明，在之前已经看到了，UDP 有 8 字节头部，后面接着数据，我们这个 UDPPacker
    里面的成员变量都是主机字节序的，通过友元函数 operator&lt;&lt;() 和 operator&gt;&gt;()
    支持串行化输入输出，并且输出后的数据包里面端口数值、长度数值，自动是按网络字节序排布。<br>
    顺便解释一下我们这个例子的图形界面，只接受源头端口、目的端口和报文消息的设置，UDPPacker 结构体的成员 m_length
    由程序自动填充，所以不提供编辑器修改报文长度，结构体成员 m_checksum 也是自动填充 0，不提供编辑器。<br>
    头文件后半截 class Widget 的声明代码全是自动生成的，不需要修改。<br>
    <br>
    接下来我们编辑源文件 widget.cpp，添加需要的功能代码，先看头文件包含和构造函数：<br>
    <div class="code"><span style=" color:#000080;">#include</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#008000;">"widget.h"</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">"ui_widget.h"</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QDebug&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QMessageBox&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QFile&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QFileDialog&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QDataStream&gt;</span><span style=" color:#c0c0c0;">  </span><span
style=" color:#008000;">//串行化数据流</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QListWidgetItem&gt;</span><span style=" color:#c0c0c0;">  </span><span
style=" color:#008000;">//从列表控件的行提取文本</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QIntValidator&gt;</span><span style=" color:#c0c0c0;">    </span><span
style=" color:#008000;">//验证端口号范围</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
style=" color:#000000;">Widget</span><span style=" color:#000000;">(</span><span
style=" color:#800080;">QWidget</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">*</span><span style=" color:#000000;">parent</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QWidget</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">parent</span><span
style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">new</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Ui</span><span style=" color:#000000;">::</span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setupUi</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//设置列表控件一次只能选一行</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">listWidget</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setSelectionMode</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QAbstractItemView</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">SingleSelection</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//新建验证器，限制源端口和目的端口范围</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QIntValidator</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#000000;">valSrc</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">new</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QIntValidator</span><span
style=" color:#000000;">(</span><span style=" color:#000080;">0</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000080;">65535</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditSrcPort</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setValidator</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">valSrc</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QIntValidator</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#000000;">valDst</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">new</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QIntValidator</span><span
style=" color:#000000;">(</span><span style=" color:#000080;">0</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000080;">65535</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditDstPort</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setValidator</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">valDst</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#800080;">Widget</span><span style=" color:#000000;">::~</span><span
style=" font-style:italic; color:#000000;">Widget</span><span style=" color:#000000;">()</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">delete</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">ui</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    包含的头文件新加了一个 &lt;QIntValidator&gt; 整数验证器，保证用户输入的端口范围位于 0 到
    65535，其他的头文件上个例子都用过，不重复说了。<br>
    在构造函数里面，我们先把列表控件设置成一次只能选一行 QAbstractItemView::SingleSelection，简化后面 "删除UDP包"
    按钮的操作代码。然后我们 new 了两个整数验证器，范围都是 0 到 65535，把整数验证器设置给源端口和目的端口的单行编辑器。<br>
    <br>
    在编写各个槽函数之前，我们在析构函数后面手动添加两个全局函数，就是 UDPPacker 结构体里面声明的两个友元函数，第一个是
    operator&lt;&lt;() 函数，用于串行化输出流：<br>
    <div class="code"><span style=" color:#008000;">//将</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#008000;">UDPPacker</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#008000;">对象串行化的全局函数</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#800080;">QDataStream</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">&amp;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">operator</span><span style=" color:#000000;">&lt;&lt;(</span><span
style=" color:#800080;">QDataStream</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">&amp;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">stream</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#808000;">const</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">UDPPacker</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">udp</span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//将数据按照规定顺序都写入流中，整型数值会自动转为网络字节序</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_srcPort</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_dstPort</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_length</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_checksum</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//写入裸的数据报文</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">writeRawData</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_data</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">data</span><span style=" color:#000000;">(),</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">udp</span><span style=" color:#000000;">.</span><span
style=" color:#800000;">m_data</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">size</span><span style=" color:#000000;">()</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//返回数据流对象</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">return</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    在我们编写输出语句时，比如 dsOut&lt;&lt;udp ，前面的 dsOut 就是上面函数参数里的 stream，udp 就是参数里第二个
    udp。<br>
    在输出时，我们输出源端口、目的端口、UDP包长度、校验和四个整型变量，QDataStream 自动把主机字节序的整型变量输出为网络字节序。<br>
    最后写入的是报文消息 udp.m_data 的裸数据，udp.m_data 裸数据的长度等会可以通过 (udp.m_length - 8)
    计算出来的，udp.m_length 就是 UDP 包头 8 字节加报文消息长度，所以没必要把报文消息的长度写入数据流。<br>
    <br>
    在输出函数末尾返回 stream 流对象，这样保证以后可以连环使用输出运算符，比如 dsOut&lt;&lt;udp1&lt;&lt;udp2。<br>
    <br>
    第二个是用于串行化输入流的 operator&gt;&gt;() 函数：<br>
    <div class="code"><span style=" color:#800080;">QDataStream</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#000000;">&amp;</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#000000;">operator</span><span style=" color:#000000;">&gt;&gt;(</span><span
        style=" color:#800080;">QDataStream</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#000000;">&amp;</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#000000;">stream</span><span style=" color:#000000;">,</span><span
        style=" color:#c0c0c0;"> </span><span style=" color:#800080;">UDPPacker</span><span
        style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
        style=" color:#c0c0c0;"> </span><span style=" color:#000000;">udp</span><span
        style=" color:#000000;">)</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//按照原来的顺序和类型读取，网络字节序自动转为主机字节序</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_srcPort</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_dstPort</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_length</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_checksum</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//读取裸的数据报文</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//readRawData参数的缓冲区必须由程序员提前分配空间</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//计算报文消息的长度</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">int</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nMsgLen</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">udp</span><span style=" color:#000000;">.</span><span style=" color:#800000;">m_length</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">-</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">8</span><span style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//减去包头</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">8</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">字节</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">char</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#000000;">buff</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">new</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">char</span><span
style=" color:#000000;">[</span><span style=" color:#000000;">nMsgLen</span><span
style=" color:#000000;">];</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">//分配空间</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">readRawData</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">buff</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nMsgLen</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span><span style=" color:#c0c0c0;">    </span><span
style=" color:#008000;">//把数据读到缓冲区</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//把缓冲区设置给</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">QByteArray</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">对象，缓冲区自动划归</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">QByteArray</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">对象管理，不要手动删除</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">buff</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">指针</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_data</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setRawData</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">buff</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nMsgLen</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//返回数据流对象</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">return</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">stream</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    在做输入时，要与输出函数里面的顺序一样，先读取四个整型变量，即源端口、目的端口和 UDP 包长度、校验和，对于整型变量输入时，QDataStream
    自动把输入源的网络字节序整型变量转为主机字节序。<br>
    使用 readRawData() 函数时需要注意，参数里的缓冲区需要程序员提前分配好，我们通过 (udp.m_length - 8)
    计算出后面消息报文裸数据的长度，然后分配 buff 缓冲区，调用 stream.readRawData() 读取消息报文的数据，最后把缓冲区指针
    buff 设置给 udp.m_data。<br>
    QByteArray::setRawData() 函数会自动接管缓冲区，不要手动删除 buff
    指向的缓冲区。QByteArray::setRawData() 函数不会新增内部缓冲区也不会执行数据拷贝，而是直接占有参数里的 buff 缓冲区，长度为
    nMsgLen 。<br>
    <br>
    在输入函数结尾也是返回 stream 流对象，用于连环输入变量。<br>
    <br>
    如果读者以后需要为自己定义的结构体或类添加串行化输入输出支持，可以按上面如法炮制，只要两个运算符函数就行了。<br>
    <br>
    接下来我们来看看几个槽函数的代码，第一个是 "添加UDP包" 按钮对应的槽函数代码：<br>
    <div class="code"><span style=" color:#808000;">void</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
        style=" color:#000000;">on_pushButtonAddUDP_clicked</span><span style=" color:#000000;">()</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取字符串</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strSrcPort</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">lineEditSrcPort</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">text</span><span style=" color:#000000;">().</span><span
style=" color:#000000;">trimmed</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strDstPort</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">lineEditDstPort</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">text</span><span style=" color:#000000;">().</span><span
style=" color:#000000;">trimmed</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strMsg</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">lineEditMsg</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">text</span><span style=" color:#000000;">().</span><span
style=" color:#000000;">trimmed</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断字符串是否为空</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strSrcPort</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">isEmpty</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">||</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strDstPort</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">isEmpty</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">||</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strMsg</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">isEmpty</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"添加包"</span><span style=" color:#000000;">),</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"请先填写两个端口和消息字符串。"</span><span style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//定义UDP包的结构体</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">UDPPacker</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">udp</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//把消息转为</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">UTF-8</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">编码的字节数组</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QByteArray</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">baMsg</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">strMsg</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">toUtf8</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//填充结构体</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_srcPort</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">strSrcPort</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">toUShort</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_dstPort</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">strDstPort</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">toUShort</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_length</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">8</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">+</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">baMsg</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">size</span><span style=" color:#000000;">();</span><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//8是包头长度</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_checksum</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">;</span><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//这里填充0，UDP校验和不是强制要求</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_data</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">baMsg</span><span style=" color:#000000;">;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//把结构体输出到一个字节数组，打成一个包</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QByteArray</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">baAll</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">(&amp;</span><span style=" color:#000000;">baAll</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QIODevice</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">ReadWrite</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">//只需要一句，就可以把复杂的结构体填充到流里面</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//baAll</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">是原始字节数组，人为不可读，转为十六进制字符串显示</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strAll</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">baAll</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">toHex</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//添加到列表控件显示</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">listWidget</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">addItem</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strAll</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    这个槽函数先获取三个单行编辑器的文本，判断文本是否为空。<br>
    对于非空文本，我们定义 UDP 包的结构体对象 udp；<br>
    把报文消息 strMsg 转为 UTF-8 编码的字节数组 baMsg ，备用；<br>
    然后填充 udp 对象的成员：源端口、目的端口，计算UDP包长度，设置校验和为 0，并把消息字节数组 baMsg 赋值给 udp.m_data。<br>
    <br>
    接下来我们定义一个内存中的输出字节数组 baAll，用于 udp 对象打包成一个整体；<br>
    定义 dsOut 输出流对象，对于输出流，应该传递字节数组 baAll 的指针，并标出读写模式；<br>
    然后只用一句代码 dsOut&lt;&lt;udp 就把整个结构体对象填充到 baAll 里面了。<br>
    <br>
    这个 baAll 其实就是一个真的 UDP 包，如果把它附加上 MAC 帧头和 IP 包头，就可以向网络中发送。<br>
    我们这里没学到网络，只是借 UDP 结构体做示范而已。<br>
    baAll 里面是二进制数据，没法直接提供给人类来看，需要把里面的每个字节都转为两个十六进制数的形式来显示，就是调用 baAll.toHex()，得到
    strAll 字符串，比如数值 0x8f 会转为两个十六进制字符 "8f" 。<br>
    原始数据包变成字符串 strAll 之后，就可以添加 strAll 到列表控件来显示了。<br>
    <br>
    第二个是 "删除UDP包" 按钮对应的槽函数代码：<br>
    <div class="code"><span style=" color:#808000;">void</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
        style=" color:#000000;">on_pushButtonDelUDP_clicked</span><span style=" color:#000000;">()</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取行号</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">int</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCurRow</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">listWidget</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">currentRow</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断行号是否合法</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCurRow</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&lt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//删除该行的</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">UDP</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">包</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">listWidget</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">takeItem</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">nCurRow</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    这段代码获取列表控件当前行号，如果行号合法才进行删除一行的操作。<br>
    <br>
    第三个是 "保存UDP" 按钮对应的槽函数，我们把列表控件里用户添加的所有行都转为 UDP 包存到文件中：<br>
    <div class="code"><span style=" color:#008000;">//把UDP包存到文件</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">on_pushButtonSave_clicked</span><span
style=" color:#000000;">()</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取行计数，并判断是否有数据行</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">int</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCount</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">listWidget</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">count</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">nCount</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&lt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">1</span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取保存文件名</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strFileName</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">QFileDialog</span><span style=" color:#000000;">::</span><span
style=" color:#000000;">getSaveFileName</span><span style=" color:#000000;">(</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#808000;">this</span><span
style=" color:#000000;">,</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"保存UDP文件"</span><span
style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"."</span><span style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"UDP</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">files(*.udp);;All</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">files(*)"</span><span style=" color:#000000;">)</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断文件名</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strFileName</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">isEmpty</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">//没文件名不保存</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//根据文件名定义文件对象</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QFile</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">fileOut</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">strFileName</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//打开</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">!</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">fileOut</span><span
style=" color:#000000;">.</span><span style=" font-style:italic; color:#000000;">open</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QIODevice</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">WriteOnly</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"保存UDP文件"</span><span style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                             </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"打开要保存的文件失败："</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">+</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">fileOut</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">errorString</span><span
style=" color:#000000;">());</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//构建串行化输出流</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#000000;">fileOut</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//不设置流的版本号，用默认的版本号</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//先写入一个整型变量，表示包个数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#800080;">qint32</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">nCount</span><span
style=" color:#000000;">);</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//用</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">for</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">循环从列表控件提取包</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">UDPPacker</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">udpCur</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">for</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">i</span><span style=" color:#000000;">=</span><span style=" color:#000080;">0</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">i</span><span
style=" color:#000000;">&lt;</span><span style=" color:#000000;">nCount</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">i</span><span
style=" color:#000000;">++)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//十六进制字符串</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strHex</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">listWidget</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">item</span><span style=" color:#000000;">(</span><span style=" color:#000000;">i</span><span
style=" color:#000000;">)-&gt;</span><span style=" color:#000000;">text</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//转为原始数据包</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QByteArray</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">baCur</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">QByteArray</span><span style=" color:#000000;">::</span><span
style=" color:#000000;">fromHex</span><span style=" color:#000000;">(</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strHex</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">toUtf8</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//根据字节数组定义输入流</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dsIn</span><span style=" color:#000000;">(</span><span
style=" color:#000000;">baCur</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//提取UDP包</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">dsIn</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">udpCur</span><span
style=" color:#000000;">;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//把原始</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">udp</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">包写入到文件中</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">udpCur</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//保存完毕</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">information</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"保存UDP包"</span><span style=" color:#000000;">),</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"保存UDP包到文件完毕！"</span><span style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    这个槽函数先获取列表控件内容的行计数，如果没内容就不处理。<br>
    列表控件有内容时，获取保存文件名，并判断获取的文件名是否为空。<br>
    说明一下，*.udp 文件的格式非常简单，我们先写入一个 UDP 包的计数变量，然后把 UDP 包依次写入文件中即可。<br>
    <br>
    得到文件名之后，先定义文件对象 fileOut 并打开，然后根据文件对象定义串行化输出流 dsOut。<br>
    这里简化操作，不设置 dsOut&nbsp; 的版本号，就用默认的值。<br>
    我们先把 UDP 包计数 nCount 写入输出流中，然后用 for 循环：<br>
    &nbsp;&nbsp;&nbsp; 从列表控件提取一行的文本 strHex，把 strHex 转为 UTF-8 编码的临时 QByteArray
    ，然后用 QByteArray::fromHex() 把十六进制数的字符串转为原始的字节数值，得到 baCur ；<br>
    &nbsp;&nbsp;&nbsp; 根据原始数值的字节数组 baCur 定义输入流 dsIn；<br>
    &nbsp;&nbsp;&nbsp; 用一句代码 dsIn&gt;&gt;udpCur 提取出数据包的结构体对象；<br>
    &nbsp;&nbsp;&nbsp; 输出结构体对象 udpCur 到文件中。<br>
    for 循环完成之后，提示用户 UDP 包保存完毕。<br>
    <br>
    这里再说一下 QDataStream 构造函数，把数据输出到一个内存字节数组，那么需要传递字节数组指针，并指明读写的模式，比如：<br>
    &nbsp;&nbsp;&nbsp; QDataStream dsOut( <span style="font-weight: bold;">&amp;</span>baAll,
    QIODevice::ReadWrite);<br>
    如果是从一个内存字节数组做输入，那么只需要传递字节数组对象给 QDataStream 构造函数就行了：<br>
    &nbsp;&nbsp;&nbsp; QDataStream dsIn( baCur );<br>
    读者可以复习一下前面 7.4.1 小节的内容，注意两个构造函数的区别。<br>
    <br>
    我们为结构体添加两个函数 operator&gt;&gt;() 和 operator&gt;&gt;()，QDataStream
    流会自动调用这两个函数做输入输出，无论是对内存字节数组的输入输出，还是对文件的输入输出，都可以自动完成对结构体的填充和输出。<br>
    <br>
    第四个是 "加载UDP" 按钮对应的槽函数代码，用于读取上面代码写入的 *.udp 文件：<br>
    <div class="code"><span style=" color:#808000;">void</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
        style=" color:#000000;">on_pushButtonLoad_clicked</span><span style=" color:#000000;">()</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取打开文件名</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strFileName</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">QFileDialog</span><span style=" color:#000000;">::</span><span
style=" color:#000000;">getOpenFileName</span><span style=" color:#000000;">(</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#808000;">this</span><span
style=" color:#000000;">,</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"打开UDP文件"</span><span
style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"."</span><span style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"UDP</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">files(*.udp);;All</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">files(*)"</span><span style=" color:#000000;">)</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断文件名</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strFileName</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">isEmpty</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//定义文件对象</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QFile</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">fileIn</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strFileName</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//打开</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">!</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">fileIn</span><span
style=" color:#000000;">.</span><span style=" font-style:italic; color:#000000;">open</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QIODevice</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">ReadOnly</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"打开UDP文件"</span><span style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                             </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"打开指定UDP文件失败："</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">+</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">fileIn</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">errorString</span><span
style=" color:#000000;">());</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//定义串行化输入流</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dsIn</span><span style=" color:#000000;">(&amp;</span><span
style=" color:#000000;">fileIn</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取数据包个数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">qint32</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCount</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">dsIn</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">nCount</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断个数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nCount</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&lt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">1</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"加载UDP包"</span><span style=" color:#000000;">),</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"指定UDP文件内数据包计数小于1，无法加载。"</span><span style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//先清空列表控件内容</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">listWidget</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">clear</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//使用</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">for</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">循环提取UDP数据包</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">UDPPacker</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">udpCur</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">for</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">int</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">i</span><span style=" color:#000000;">=</span><span
style=" color:#000080;">0</span><span style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">i</span><span style=" color:#000000;">&lt;</span><span style=" color:#000000;">nCount</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">i</span><span
style=" color:#000000;">++</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//先判断流的状态，状态不对就结束循环</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dsIn</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">status</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">!=</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Ok</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">            </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"读取第</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">%1</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">个数据包前的状态错误：%2"</span><span
style=" color:#000000;">).</span><span style=" color:#000000;">arg</span><span style=" color:#000000;">(</span><span
style=" color:#000000;">i</span><span style=" color:#000000;">).</span><span style=" color:#000000;">arg</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">dsIn</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">status</span><span style=" color:#000000;">());</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">            </span><span style=" color:#808000;">break</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//提取UDP数据包</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">dsIn</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">udpCur</span><span
style=" color:#000000;">;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//把UDP数据包的内容打包成一个</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">QByteArray</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QByteArray</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">baCur</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">(&amp;</span><span style=" color:#000000;">baCur</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QIODevice</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">ReadWrite</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000000;">dsOut</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">udpCur</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//把原始字节数组转成十六进制字符串</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strHex</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">baCur</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">toHex</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//添加到列表控件显示</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">listWidget</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">addItem</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strHex</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//提示加载完毕</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">information</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"加载UDP包"</span><span style=" color:#000000;">),</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"加载文件中的UDP包完成！"</span><span style=" color:#000000;">));</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    这个槽函数先获取要打开的文件名，判断文件名是否为空；<br>
    有文件名之后定义文件对象 fileIn，打开该文件；<br>
    根据文件对象定义串行化输入流 dsIn；<br>
    从输入流读取 UDP 包的计数 nCount ，并判断一下计数是否有 UDP 包；<br>
    在加载文件中的 UDP 包之前，先清空列表控件中的内容，准备显示新数据；<br>
    利用 for 循环：<br>
    &nbsp;&nbsp;&nbsp; 先判断输入流的状态，如果状态不对就跳出循环；<br>
    &nbsp;&nbsp;&nbsp; 然后从文件输入流中逐个提取 UDP 包结构体，填充到 udpCur；<br>
    &nbsp;&nbsp;&nbsp; 定义内存字节数组 baCur，并根据这个 baCur 定义输出流 dsOut；<br>
    &nbsp;&nbsp;&nbsp; 把结构体对象 udpCur 输出到 dsOut，就是把结构体对象打包成一个字节数组 baCur；<br>
    &nbsp;&nbsp;&nbsp; 把原始字节数组 baCur 转为十六进制字符串 strHex ，显示到列表控件；<br>
    在 for 循环处理完毕之后，用消息框提示加载完成。<br>
    <br>
    加载过程就是从文件提取各个 UDP 结构体对象，转为一个原始数值的字节数组，再转为人类可读的十六进制字符串显示到列表控件。<br>
    <br>
    最后一个槽函数是关于列表控件的，当列表控件选中的行变化时，我们从当前行字符串中提取 UDP 包，并显示源端口、目的端口和报文消息到三个单行编辑器里面：<br>
    <div class="code"><span style=" color:#808000;">void</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
        style=" color:#000000;">on_listWidget_currentRowChanged</span><span style=" color:#000000;">(</span><span
        style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span
        style=" color:#000000;">currentRow</span><span style=" color:#000000;">)</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断行号是否合法</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">currentRow</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&lt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//提取十六进制字符串</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strHex</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">listWidget</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">item</span><span style=" color:#000000;">(</span><span style=" color:#000000;">currentRow</span><span
style=" color:#000000;">)-&gt;</span><span style=" color:#000000;">text</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//转为原始数据包</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QByteArray</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">baAll</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">QByteArray</span><span style=" color:#000000;">::</span><span
style=" color:#000000;">fromHex</span><span style=" color:#000000;">(</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strHex</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">toUtf8</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//构造输入流</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QDataStream</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">dsIn</span><span style=" color:#000000;">(</span><span
style=" color:#000000;">baAll</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//定义UDP结构体对象</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">UDPPacker</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">udp</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">dsIn</span><span
style=" color:#000000;">&gt;&gt;</span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;">      </span><span
style=" color:#008000;">//只需要一句，就可以从字节数组提取</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">UDP</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">结构体对象</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//显示到三个编辑器里面</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditSrcPort</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"%1"</span><span style=" color:#000000;">).</span><span
style=" color:#000000;">arg</span><span style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">udp</span><span style=" color:#000000;">.</span><span style=" color:#800000;">m_srcPort</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditDstPort</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"%1"</span><span style=" color:#000000;">).</span><span
style=" color:#000000;">arg</span><span style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">udp</span><span style=" color:#000000;">.</span><span style=" color:#800000;">m_dstPort</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditMsg</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QString</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">fromUtf8</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">udp</span><span
style=" color:#000000;">.</span><span style=" color:#800000;">m_data</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    这个槽函数先判断当前行号是否合法，不合法就返回；<br>
    然后取出列表控件当前行的文本，存到 strHex ；<br>
    把 strHex 转为 UTF-8 编码的临时 QByteArray，利用 QByteArray::fromHex() 把十六进制字符串转为原始数值的字
    节数组 baAll ；<br>
    然后根据 baAll 定义输入流 dsIn；<br>
    从输入流提取数据填充到 udp 对象；<br>
    然后把源端口、目的端口、报文消息显示到各自对应的单行编辑器里面。<br>
    <br>
    例子的代码就是上面那些，本节第二个例子代码与第一个例子代码有些相似，主要是供读者多练手，学习串行化数据流 QDataStream 的用法。<br>
    <br>
    第二个例子生成运行之后，我们可以手动添加几个 UDP 数据包：<br>
    <center> <img src="images/ch07/ch07-04-10.png" alt="run"> </center>
    "保存UDP" 和 "加载UDP" 等功能，读者可以自行测试一下。<br>
    <br>
    本节的内容就到这，上一节的文本流和本节的串行化数据流最常用，一定要熟练运用。下一节我们介绍其他几个文件读写相关的类，内容相对简单一些。<br>
    <br>
    <br>
    <br>
    <table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
      <tbody>
        <tr>
          <td style="width: 40%;">
            <div style="text-align: center;"><a href="ch07-03.htm"><img class="pic"
                  style="width: 32px; height: 32px;" alt="prev" src="images/pics/prev.png"></a></div>
          </td>
          <td style="width: 20%;">
            <div style="text-align: center;"><a href="contents.htm"><img class="pic"
                  style="width: 32px; height: 32px;" alt="contents" src="images/pics/contents.png"></a></div>
          </td>
          <td style="width: 40%;">
            <div style="text-align: center;"><a href="ch07-05.htm"><img class="pic"
                  style="width: 32px; height: 32px;" alt="next" src="images/pics/next.png"></a></div>
          </td>
        </tr>
      </tbody>
    </table>
  </body>
</html>
